package com.yy.util.http;

import android.util.Log;

import org.apache.http.HttpStatus;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

/**
 * Created by zhangly on 2015/4/17.
 */
public class HttpUtil {

    private static final String TAG = HttpUtil.class.getSimpleName();

    public static final String PNG_URL = "http://upload.hifi33.com/images/201003/201003152325309954.jpg";

    private final static int RECONNECT = 3;
    private final static int REQ_MODE_HTTP = 0;
    private final static int REQ_MODE_HTTPS = 1;

    public static InputStream httpGet(String url) {
        return httpGet(url, null, REQ_MODE_HTTP, null);
    }

    public static InputStream httpGet(String url, Map<String, Object> params) {
        return httpGet(url, params, REQ_MODE_HTTP, null);
    }

    public static InputStream httpsGet(String url, InputStream cerFile) {
        return httpGet(url, null, REQ_MODE_HTTPS, cerFile);
    }

    public static InputStream httpsGet(String url, Map<String, Object> params, InputStream cerFile) {
        return httpGet(url, params, REQ_MODE_HTTPS, cerFile);
    }


    public static InputStream httpPost(String url, Map<String, Object> params) {
        return httpPost(url, params, REQ_MODE_HTTP, null);
    }

    public static InputStream httpsPost(String url, Map<String, Object> params, InputStream cerFile) {
        return httpPost(url, params, REQ_MODE_HTTPS, cerFile);
    }

    /*private static HttpURLConnection openHttpURLConnection(String url) {
        return openHttpURLConnection(url, REQ_MODE_HTTP, null);
    }*/

    private static boolean waitReconnect(int reconnectIndex) {
        if(reconnectIndex < RECONNECT) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return true;
        }
        return false;
    }

    private static String makeUrl(String url, Map<String, Object> params) {
        StringBuilder sbUrl = new StringBuilder(url);
        if(params != null && !params.isEmpty()) {
            if(!url.contains("?")) {
                sbUrl.append('?');
            }
            for(String name : params.keySet()){
                sbUrl.append('&');
                sbUrl.append(name);
                sbUrl.append('=');
                sbUrl.append(String.valueOf(params.get(name)));
                //不做URLEncoder处理
                //url.append(URLEncoder.encode(String.valueOf(params.get(name)), UTF_8));
            }
        }
        return sbUrl.toString().replace("?&", "?");
    }

    private static byte[] makeParams2Byte(Map<String, Object> params) {
        StringBuilder sb = new StringBuilder();
        if(params != null && !params.isEmpty()) {
            for (Map.Entry<String, Object> itemParam : params.entrySet()) {
                sb.append(itemParam.getKey());
                sb.append("=");
                sb.append(itemParam.getValue());
                sb.append("&");
            }
            sb.deleteCharAt(sb.length() - 1);
            return sb.toString().getBytes();
        }
        return null;
    }

    private static HttpURLConnection openHttpURLConnection(String url, int reqMode, InputStream cerFile) {
        HttpURLConnection connection = null;
        try {
            switch (reqMode) {
                case REQ_MODE_HTTP:
                    connection = (HttpURLConnection) new URL(url).openConnection();
                    break;
                case REQ_MODE_HTTPS:
                    connection = getHttpsURLConnection(cerFile, url);
                    break;
            }
            connection.setDoInput(true);
            connection.setConnectTimeout(30000);
            connection.setRequestProperty("Accept-Charset", "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return connection;
    }

    private static HttpURLConnection getHttpsURLConnection(InputStream cerFile, String url) {
        HttpsURLConnection connection = null;
        try {
            connection = (HttpsURLConnection) new URL(url).openConnection();
            CertificateFactory cerInstance = CertificateFactory.getInstance("X.509");
            Certificate certificate = cerInstance.generateCertificate(cerFile);

            KeyStore keyInstance = KeyStore.getInstance(KeyStore.getDefaultType());
            keyInstance.load(null, null);
            keyInstance.setCertificateEntry("cer", certificate);

            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory trustInstance = TrustManagerFactory.getInstance(algorithm);
            trustInstance.init(keyInstance);

            SSLContext sslInstance = SSLContext.getInstance("TLS");
            sslInstance.init(null, trustInstance.getTrustManagers(), null);
            connection.setSSLSocketFactory(sslInstance.getSocketFactory());
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return connection;
    }

    private static InputStream httpPost(String url, Map<String, Object> params, int reqMode, InputStream cerFile) {
        int reconnectIndex = 0;
        HttpURLConnection connection = openHttpURLConnection(url, reqMode, cerFile);
        connection.setDoOutput(true);
        OutputStream outputStream = null;
        try {
            connection.setRequestMethod("POST");
        } catch (ProtocolException e) {
            e.printStackTrace();
        }
        do {
            try {
                outputStream = connection.getOutputStream();
                if(params != null) {
                    outputStream.write(makeParams2Byte(params));
                }
                outputStream.flush();
                outputStream.close();
                connection.connect();
                int code = connection.getResponseCode();
                if(code == HttpStatus.SC_OK) {
                    return connection.getInputStream();
                }
            } catch(SocketTimeoutException e) {
                reconnectIndex++;
                if(waitReconnect(reconnectIndex)) {
                    continue;
                }
            } catch (IOException e) {
                e.printStackTrace();
                reconnectIndex++;
                if(waitReconnect(reconnectIndex)) {
                    continue;
                }
            }
        } while(reconnectIndex <= RECONNECT);
        return null;
    }

    private static InputStream httpGet(String url, Map<String, Object> params, int reqMode, InputStream cerFile) {
        Log.i(TAG, "--->>" + makeUrl(url, params));
        int reconnectIndex = 0;
        HttpURLConnection connection = openHttpURLConnection(makeUrl(url, params), reqMode, cerFile);
        try {
            connection.setRequestMethod("GET");
        } catch (ProtocolException e) {
            e.printStackTrace();
        }
        do {
            try {
                connection.connect();
                int code = connection.getResponseCode();
                Log.i(TAG, "--->>" + code);
                if(code == HttpStatus.SC_OK) {
                    return connection.getInputStream();
                }
            } catch (SocketTimeoutException e) {
                e.printStackTrace();
                reconnectIndex++;
                if(waitReconnect(reconnectIndex)) {
                    Log.i(TAG, "请求出现异常, 正尝试第" + (reconnectIndex + 1) + "次" + "重连");
                    continue;
                }
            } catch (IOException e) {
                e.printStackTrace();
                reconnectIndex++;
                if(waitReconnect(reconnectIndex)) {
                    Log.i(TAG, "请求出现异常, 正尝试第" + (reconnectIndex + 1) + "次" + "重连");
                    continue;
                }
            }
        } while(reconnectIndex <= RECONNECT);

        return null;
    }
}
